using System;
using SharpObjects.Configuration.ConfigurationProviders;
using SharpObjects.EventBus;
using SharpObjects.Instantiation.Services;
using SharpObjects.Interfaces;
using SharpObjects.Shared.ApplicationEvents;

namespace SharpObjects.Configuration.Services
{
    public class ConfigurableServiceFactory : ServiceFactory, IXmlInitializable, IDisposable  
    {
        protected string eventBusId = null;
        protected IEventBus eventBus = null;

        public ConfigurableServiceFactory()
        {
        }

        public ConfigurableServiceFactory(IEventBus eventBus)
        {
            this.eventBus = eventBus;
        }

        #region IXmlInitializable Members

        public void Initialize(System.Xml.XmlElement initializationElement)
        {
            IConfigurationProvider init = new XmlConfigurationProvider(initializationElement);

            IServiceDescriptor[] serviceDescriptors = init.GetObjects<IServiceDescriptor>("service_descriptor");
            Initialize(serviceDescriptors);

            this.eventBusId = init.GetString("event_bus_id", init.GetString("@event_bus_id", null));

            if (this.eventBusId != null)
            {
                this.eventBus = ServiceFactory.Instance.GetService<IEventBus>(this.eventBusId);
                this.eventBus.ApplicationEvent += new ApplicationEventHandler(eventBus_ApplicationEvent);
            }

            this.IsInitialized = true;
        }

        void eventBus_ApplicationEvent(object applicationEvent)
        {
           if(applicationEvent is ServiceFactoryGetServiceApplicationEvent)
           {
               ServiceFactoryGetServiceApplicationEvent getServiceApplicationEvent = (ServiceFactoryGetServiceApplicationEvent)applicationEvent;

               getServiceApplicationEvent.Service = this.GetService<object>(getServiceApplicationEvent.ServiceId,
                                                                            getServiceApplicationEvent.ServiceVersion);
           }
        }

        private bool isInitialized = false;

        public bool IsInitialized
        {
            get
            {
                lock (this)
                {
                    return this.isInitialized;
                }
            }
            set
            {
                lock (this)
                {
                    this.isInitialized = value;
                }
            }
        }

        #endregion

        protected override T GetServiceFromServiceDescriptor<T>(IServiceDescriptor serviceDescriptor, string serviceVersion)
        {
            T service = base.GetServiceFromServiceDescriptor<T>(serviceDescriptor, serviceVersion);

            if (service is IXmlInitializable && serviceDescriptor is ConfigurableServiceDescriptor)
            {
                ConfigurableServiceDescriptor configurableServiceDescriptor = (ConfigurableServiceDescriptor)serviceDescriptor;

                if (configurableServiceDescriptor.ServiceInitializationElement != null)
                {
                    IXmlInitializable iobject = (IXmlInitializable)service;

                    if (!iobject.IsInitialized)
                    {
                        iobject.Initialize(configurableServiceDescriptor.ServiceInitializationElement);
                    }
                }
            }

            return service;
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (this.IsInitialized)
            {
                if (this.eventBus != null)
                {
                    this.eventBus.ApplicationEvent -= new ApplicationEventHandler(eventBus_ApplicationEvent);
                }

                this.IsInitialized = false;
            }
        }

        #endregion
    }
}